package com.starblink.android.basic.ext

import android.animation.Animator
import android.animation.IntEvaluator
import android.animation.ValueAnimator
import android.content.res.TypedArray
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Outline
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider
import androidx.annotation.ColorInt
import androidx.recyclerview.widget.RecyclerView
import com.starblink.android.basic.network.base.BaseApiClient
import com.starblink.basic.util.CommUtils
import com.starblink.basic.util.log.YYLogUtils
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch

/**
 * View相关

view.width(100)           // 设置View的宽度为100
view.widthAndHeight(100)  // 改变View的宽度和高度为100
view.animateWidthAndHeight(600,900) //带有动画
view.animateWidth(600,900, action = { //监听动画进度，执行可选操作 }) //带有动画
view.margin(leftMargin = 100)  // 设置View左边距为100
view.click { toast("aa") }    // 设置点击监听，已实现事件节流，350毫秒内只能点击一次
view.longClick {             // 设置长按监听
toast("long click")
true
}
view.gone()
view.visible()
view.invisible()
view.isGone  // 属性
view.isVisible // 属性
view.isInvisible // 属性
view.toggleVisibility() // 切换可见性
view.toBitmap()           // 获取View的截图，支持RecyclerView长列表截图
// 遍历子View
layout.children.forEachIndexed { index, view ->

}
 */

/**
 * 设置View的高度
 */
fun View.height(height: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
    )
    params.height = height
    layoutParams = params
    return this
}

/**
 * 设置View高度，限制在min和max范围之内
 * @param h
 * @param min 最小高度
 * @param max 最大高度
 */
fun View.limitHeight(h: Int, min: Int, max: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
    )
    when {
        h < min -> params.height = min
        h > max -> params.height = max
        else -> params.height = h
    }
    layoutParams = params
    return this
}

/**
 * 设置View的宽度
 */
fun View.width(width: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
    )
    params.width = width
    layoutParams = params
    return this
}

/**
 * 设置View宽度，限制在min和max范围之内
 * @param w
 * @param min 最小宽度
 * @param max 最大宽度
 */
fun View.limitWidth(w: Int, min: Int, max: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
    )
    when {
        w < min -> params.width = min
        w > max -> params.width = max
        else -> params.width = w
    }
    layoutParams = params
    return this
}

/**
 * 设置View的宽度和高度
 * @param width 要设置的宽度
 * @param height 要设置的高度
 */
fun View.widthAndHeight(width: Int, height: Int): View {
    val params = layoutParams ?: ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.WRAP_CONTENT
    )
    params.width = width
    params.height = height
    layoutParams = params
    return this
}

/**
 * 设置View的margin
 * @param leftMargin 默认保留原来的
 * @param topMargin 默认是保留原来的
 * @param rightMargin 默认是保留原来的
 * @param bottomMargin 默认是保留原来的
 */
fun View.margin(
    leftMargin: Int = Int.MAX_VALUE,
    topMargin: Int = Int.MAX_VALUE,
    rightMargin: Int = Int.MAX_VALUE,
    bottomMargin: Int = Int.MAX_VALUE
): View {
    val params = layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != Int.MAX_VALUE)
        params.leftMargin = leftMargin
    if (topMargin != Int.MAX_VALUE)
        params.topMargin = topMargin
    if (rightMargin != Int.MAX_VALUE)
        params.rightMargin = rightMargin
    if (bottomMargin != Int.MAX_VALUE)
        params.bottomMargin = bottomMargin
    layoutParams = params
    return this
}

/**
 * 设置宽度，带有过渡动画
 * @param targetValue 目标宽度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateWidth(
    targetValue: Int, duration: Long = 400, listener: Animator.AnimatorListener? = null,
    action: ((Float) -> Unit)? = null
) {
    post {
        ValueAnimator.ofInt(width, targetValue).apply {
            addUpdateListener {
                width(it.animatedValue as Int)
                action?.invoke((it.animatedFraction))
            }
            if (listener != null) addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置高度，带有过渡动画
 * @param targetValue 目标高度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateHeight(
    targetValue: Int,
    duration: Long = 400,
    listener: Animator.AnimatorListener? = null,
    action: ((Float) -> Unit)? = null
) {
    post {
        ValueAnimator.ofInt(height, targetValue).apply {
            addUpdateListener {
                height(it.animatedValue as Int)
                action?.invoke((it.animatedFraction))
            }
            if (listener != null) addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置宽度和高度，带有过渡动画
 * @param targetWidth 目标宽度
 * @param targetHeight 目标高度
 * @param duration 时长
 * @param action 可选行为
 */
fun View.animateWidthAndHeight(
    targetWidth: Int,
    targetHeight: Int,
    duration: Long = 400,
    listener: Animator.AnimatorListener? = null,
    action: ((Float) -> Unit)? = null
) {
    post {
        val startHeight = height
        val evaluator = IntEvaluator()
        ValueAnimator.ofInt(width, targetWidth).apply {
            addUpdateListener {
                widthAndHeight(
                    it.animatedValue as Int,
                    evaluator.evaluate(it.animatedFraction, startHeight, targetHeight)
                )
                action?.invoke((it.animatedFraction))
            }
            if (listener != null) addListener(listener)
            setDuration(duration)
            start()
        }
    }
}

/**
 * 设置点击监听, 并实现事件节流
 */
var _viewClickFlag = false
var _clickRunnable = Runnable {
    _viewClickFlag = false
//    Log.e("setOnClickListener","===11===$_viewClickFlag")
}

fun View.click(action: (view: View) -> Unit) {
    setOnClickListener {
        if (!_viewClickFlag) {
            _viewClickFlag = true
            action(it)
        }
        CommUtils.getHandler().removeCallbacks(_clickRunnable)
        CommUtils.getHandler().postDelayed(_clickRunnable, 500)
    }
}


/**
 * 设置长按监听
 */
fun View.longClick(action: (view: View) -> Boolean) {
    setOnLongClickListener {
        action(it)
    }
}


/*** 可见性相关 ****/
fun View.gone() {
    visibility = View.GONE
}

fun View.visible() {
    visibility = View.VISIBLE
}

fun View.invisible() {
    visibility = View.INVISIBLE
}

val View.isGone: Boolean
    get() {
        return visibility == View.GONE
    }

val View.isVisible: Boolean
    get() {
        return visibility == View.VISIBLE
    }

val View.isInvisible: Boolean
    get() {
        return visibility == View.INVISIBLE
    }

/**
 * 切换View的可见性
 */
fun View.toggleVisibility() {
    visibility = if (visibility == View.GONE) View.VISIBLE else View.GONE
}


/**
 * 获取View的截图, 支持获取整个RecyclerView列表的长截图
 * 注意：调用该方法时，请确保View已经测量完毕，如果宽高为0，则将返回null，记得判断null，否则可能导致异常
 */
fun View.toBitmap2LayoutEnhanced(@ColorInt bgColor: Int = Color.WHITE): Bitmap? {
    if (measuredWidth == 0 || measuredHeight == 0) {
        return null
    }
    when (this) {
        is RecyclerView -> {
            this.scrollToPosition(0)
            this.measure(
                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            )

            val bmp = Bitmap.createBitmap(width, measuredHeight, Bitmap.Config.ARGB_8888)
            val canvas = Canvas(bmp)

            //draw default bg, otherwise will be black
            if (background != null) {
                background.setBounds(0, 0, width, measuredHeight)
                background.draw(canvas)
            } else {
                canvas.drawColor(bgColor)
            }
            this.draw(canvas)
            //恢复高度
            this.measure(
                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)
            )
            return bmp
        }

        else -> {
            //实际情况 measuredHeight会比height矮一点 原因不明 非常奇怪 加了个判断↓
            val screenshot =
                Bitmap.createBitmap(
                    width,
                    if (height > measuredHeight) height else measuredHeight,
                    Bitmap.Config.ARGB_8888
                )
            val canvas = Canvas(screenshot)
            if (background != null ) {
                background.setBounds(
                    0,
                    0,
                    width,
                    if (height > measuredHeight) height else measuredHeight
                )
                background.draw(canvas)
            } else {
                canvas.drawColor(bgColor)
            }
            draw(canvas)// 将 view 画到画布上
            return screenshot
        }
    }
}


// 所有子View
inline val ViewGroup.children
    get() = (0 until childCount).map { getChildAt(it) }

fun ViewGroup.createChildView(layoutId: Int, attach: Boolean = false): View =
    LayoutInflater.from(this.context).inflate(layoutId, this, attach)

val View.inflater: LayoutInflater
    get() = LayoutInflater.from(this.context)

/**
 * 圆角
 */
fun View.enableCorner(radius: Int, radiusType: String = "all") {
    clipToOutline = true
    outlineProvider = object : ViewOutlineProvider() {
        override fun getOutline(view: View, outline: Outline) {
            when (radiusType) {
                "top" -> {
                    outline.setRoundRect(0, 0, width, height + radius, radius.toFloat())
                }

                "bottom" -> {
                    outline.setRoundRect(0, -radius, width, height, radius.toFloat())
                }

                "left" -> {
                    outline.setRoundRect(0, 0, width + radius, height, radius.toFloat())
                }

                "right" -> {
                    outline.setRoundRect(-radius, 0, width, height, radius.toFloat())
                }

                "topLeft" -> {
                    outline.setRoundRect(0, 0, width + radius, height + radius, radius.toFloat())
                }

                "topRight" -> {
                    outline.setRoundRect(-radius, 0, width, height + radius, radius.toFloat())
                }

                "bottomLeft" -> {
                    outline.setRoundRect(0, -radius, width + radius, height, radius.toFloat())
                }

                "bottomRight" -> {
                    outline.setRoundRect(-radius, -radius, width, height, radius.toFloat())
                }

                else -> {
                    outline.setRoundRect(0, 0, width, height, radius.toFloat())
                }
            }
        }
    }
}

/** toast相关 **/
fun toast(msg: String?) {
    ToastBussUtils.makeText(CommUtils.getContext(), msg)
}

fun toastWishlist(msg: String?) {
    ToastBussUtils.showToastWishListCenter(CommUtils.getContext(), msg)
}


fun toastShowDev(msg: String?, show: Boolean = true) {
    if (show) {
//        ToastBussUtils.makeText(CommUtils.getContext(), "测试模式：$msg")
        YYLogUtils.e("测试模式：$msg")
    }
}

fun toastShowDev1(msg: String?) {
    if (!BaseApiClient.isPub()) {
//        ToastBussUtils.makeText(CommUtils.getContext(), "测试模式：$msg")
        YYLogUtils.e("测试模式：$msg")
    }
}

//主线程toast
fun toastUI(msg: String?) {
    MainScope().launch {
        toast(msg)
    }
}

fun toast(res: Int) {
    ToastBussUtils.makeText(CommUtils.getContext(), res)
}

fun toastUI(res: Int) {
    MainScope().launch {
        toast(res)
    }
}

fun toastWarning(msg: String?) {
    ToastBussUtils.showWarning(CommUtils.getContext(), msg)
}

fun toastWarningL(msg: String?) {
    ToastBussUtils.showWarning(CommUtils.getContext(), msg, true)
}

fun toastErrLong(msg: String?) {
    ToastBussUtils.showFailText(CommUtils.getContext(), msg, true)
}


fun toastError(msg: String?) {
    ToastBussUtils.showFailText(CommUtils.getContext(), msg)
}

fun toastError(res: Int) {
    ToastBussUtils.showFailText(CommUtils.getContext(), res)
}

fun toastSuccess(msg: String?) {
    ToastBussUtils.showSuccessText(CommUtils.getContext(), msg)
}

fun toastSuccess(res: Int) {
    ToastBussUtils.showSuccessText(CommUtils.getContext(), res)
}

fun View.disableCorner() {
    clipToOutline = false
}

/**
 * 显示或隐藏，
 * @param visibleDo 只会在显示执行
 */
inline fun <T : View> T.visibleOrGone(
    visible: Boolean,
    goneMode: Int = View.GONE,
    crossinline visibleDo: (T.() -> Unit)
) {
    visibility = if (visible) {
        visibleDo.invoke(this)
        View.VISIBLE
    } else goneMode
}

inline fun <T : View> T.visibleOrGone(visible: Boolean) {
    visibility = if (visible) {
        View.VISIBLE
    } else View.GONE
}

fun <T : View> T.visibleOrInVisible(visible: Boolean) {
    visibility = if (visible) {
        View.VISIBLE
    } else View.INVISIBLE
}


/**
 *
 *一个控件在其整个屏幕上的坐标位置
 */
fun <T : View> T.locationOnScreen(
): IntArray? {
    return if (visibility == View.VISIBLE) {
        val location = intArrayOf(0, 0)
        getLocationOnScreen(location)
        YYLogUtils.e("locationOnScreen 得到坐标--->${location[0]}，${location[1]}")
        location
    } else {
        YYLogUtils.e("locationOnScreen 未得到坐标--->")
        null
    }
}


/**
 *
 *一个控件相对其父控件窗口的坐标位置
 */
fun <T : View> T.locationOnWindow(
): IntArray? {
    return if (visibility == View.VISIBLE) {
        val location = intArrayOf(0, 0)
        getLocationInWindow(location)
        YYLogUtils.e("locationOnWindow 得到坐标--->${location[0]}，${location[1]}")
        location
    } else {
        YYLogUtils.e("locationOnWindow 未得到坐标--->")
        null
    }
}

inline fun <reified T : Enum<T>> TypedArray.getEnum(index: Int, default: T?): T? {
    return getInt(index, -1).let {
        if (it >= 0) enumValues<T>()[it] else default
    }
}